package org.trc.traffic.analysis;

import java.util.HashMap;
import org.trc.traffic.AggLinkTraffic;

import com.vividsolutions.jts.geom.Envelope;

public interface CongestionCluster {
		
}

//
class CommonCongestionCluster implements CongestionCluster {
	public String clusterID = null;
	
	public int linkNum;

	public int aggDur;

	private HashMap<String, LinkAggTraffic> linkTrafficSet = new HashMap<String, LinkAggTraffic>();

	public CommonCongestionCluster(String clusterID) {
		this.clusterID = clusterID;
	}

	public void add(AggLinkTraffic linkTraffic) {
		//float speed = 0;
		if (linkTrafficSet.containsKey(linkTraffic.linkID)) {
			LinkAggTraffic aggLinkTraffic = linkTrafficSet.get(linkTraffic.linkID);
			aggLinkTraffic.dur += linkTraffic.dur;
			//speed = (linkTraffic.dur / dur) * linkTraffic.avgSpeed + (aggLinkTraffic.dur / dur) * aggLinkTraffic.speed;
			//aggLinkTraffic.speed = speed;
		} else {
			linkTrafficSet.put(linkTraffic.linkID, new LinkAggTraffic(linkTraffic.linkID, linkTraffic.dur));
			linkNum++;
		}

		aggDur += linkTraffic.dur;
	}

	public String[] getLinkIDList() {
		String[] linkIDList = new String[linkNum];
		linkTrafficSet.keySet().toArray(linkIDList);
		return linkIDList;
	}

	public int getLinkAggDur(String linkID) {
		return linkTrafficSet.get(linkID).dur;
	}

}

//Link_Cluster:(linkid, <sTime, eTime>, Dur)

class LinkCongestionCluster implements CongestionCluster {
	public String clusterID = null;
	
	public String linkid = null;
	
	public int startTime = Integer.MAX_VALUE;
	public int endTime = Integer.MIN_VALUE;
	
	public int dur;

	public LinkCongestionCluster(String clusterID){
		this.clusterID  = clusterID;		
	}
	
	public void add(AggLinkTraffic linkTraffic) {
		int linkTimeStamp = linkTraffic.hour *12 + linkTraffic.timeInterval;
		
		if(linkTimeStamp < startTime)
			startTime = linkTimeStamp;
		
		if(linkTimeStamp > endTime)
			endTime = linkTimeStamp;
		
		dur = this.endTime - this.startTime + 1;
	}

}

//Road_Cluster:(<Multilinkid, soffset, eoffset>, <sTime, eTime>, <linkid_1, dur_1, ....linkid_n, dur_n>)

class MLinkCongestionCluster implements CongestionCluster {
	public String clusterID = null;
	
	public String mLinkID = null;
	
	public float startOffset = Float.MAX_VALUE;	
	public float endOffset = Float.MIN_VALUE;
	
	public int startTime = Integer.MAX_VALUE;
	public int endTime = Integer.MIN_VALUE;
		
	public HashMap<String, LinkAggTraffic> linkTrafficSet = new HashMap<String, LinkAggTraffic>();
	
	public int dur; 
	
	public float length;
	
	public MLinkCongestionCluster(String clusterID){
		this.clusterID  = clusterID;		
	}
	
	public void add(LinkCongestionCluster linkCluster, float linkSOffset, float linkEOffset) {
		
		//System.out.println(clusterID + ": Accept linkid: " + linkCluster.linkid + ", STIME:" + (linkCluster.startTime-96) +  ", ETIME:" + (linkCluster.endTime-96));
		
		this.startTime = linkCluster.startTime < this.startTime ? linkCluster.startTime : this.startTime;

		this.endTime = linkCluster.endTime > this.endTime ? linkCluster.endTime :  this.endTime;
			
		this.startOffset = linkSOffset < this.startOffset ? linkSOffset : this.startOffset;
			
		this.endOffset = linkEOffset > this.endOffset ? linkEOffset : this.endOffset;
		
		if(linkTrafficSet.get(linkCluster.linkid)== null){
			
			linkTrafficSet.put(linkCluster.linkid, new LinkAggTraffic(linkCluster.linkid, linkCluster.dur));
		
		}else {
			
			linkTrafficSet.get(linkCluster.linkid).dur += linkCluster.dur;
			
		}
		
		this.dur = this.endTime - this.startTime + 1;
		
		this.length = this.endOffset - this.startOffset;
	}
	
}

//Region_Cluster:(MBR, <sTime, eTime>, <MLink_location, startTime, endTime； ....MLink_location_n, startTime, endTime；>)

class RegionCongestionCluster implements CongestionCluster {
	public String clusterID = null;
	
	public String regionID = null;

	public Envelope MBR;
	
	public int startTime = Integer.MAX_VALUE;
	public int endTime = Integer.MIN_VALUE;
	
	public HashMap<String, MLinkAggTraffic> mLinkTrafficSet = new HashMap<String, MLinkAggTraffic>();
	
	public HashMap<String, LinkAggTraffic> linkTrafficSet = new HashMap<String, LinkAggTraffic>();
	
	public int mLinkNum;
	
	public float totalLength;	
	
	public int dur;

	public RegionCongestionCluster(String clusterID, String spatialID){
		this.clusterID  = clusterID;
		this.regionID = spatialID;
	}
		
	public void add(MLinkCongestionCluster mlCluster, Envelope mbr) {
		//时间扩展
		this.startTime = mlCluster.startTime < this.startTime ? mlCluster.startTime : this.startTime;

		this.endTime = mlCluster.endTime > this.endTime ? mlCluster.endTime :  this.endTime;
		
		//MBR扩展
		if(MBR == null)
			this.MBR = mbr;
		else
			this.MBR.expandToInclude(mbr);
				
		//聚集
		MLinkAggTraffic mlAggTraffic = this.mLinkTrafficSet.get(mlCluster.mLinkID);
		
		if(mlAggTraffic == null) {
			
			mLinkTrafficSet.put(mlCluster.mLinkID, new MLinkAggTraffic(mlCluster.mLinkID, mlCluster.startOffset, mlCluster.endOffset, mlCluster.startTime, mlCluster.endTime));
		
			mLinkNum++;
			
		}else {//作了简化处理
			
			mlAggTraffic.startOffset = mlCluster.startOffset < mlAggTraffic.startOffset ? mlCluster.startOffset : mlAggTraffic.startOffset;
		
		    mlAggTraffic.endOffset = mlCluster.endOffset > mlAggTraffic.endOffset ? mlCluster.endOffset : mlAggTraffic.endOffset;
		    
			mlAggTraffic.startTime = mlCluster.startTime < mlAggTraffic.startTime ? mlCluster.startTime : mlAggTraffic.startTime;
			
		    mlAggTraffic.endTime = mlCluster.endTime > mlAggTraffic.endTime ? mlCluster.endTime : mlAggTraffic.endTime;
		    
		    mlAggTraffic.dur = (mlAggTraffic.endTime - mlAggTraffic.startTime) + 1; 
		    
		    mlAggTraffic.num++;
		    
		}
		
		for(LinkAggTraffic linkAggTraffic : mlCluster.linkTrafficSet.values()){
			if(linkTrafficSet.get(linkAggTraffic.linkID)== null){
				
				linkTrafficSet.put(linkAggTraffic.linkID, linkAggTraffic);
			
			}else {
				
				linkTrafficSet.get(linkAggTraffic.linkID).dur += linkAggTraffic.dur;
				
			}
		}
		

		
		
		this.dur = this.endTime - this.startTime + 1;
	}
   
	public float getTotalRoadLength(){
		float length = 0.0f;
		
		for(MLinkAggTraffic mlc : mLinkTrafficSet.values())
			length += mlc.endOffset - mlc.startOffset;
			
		return length;
	}

}

//路段的聚集度量 
class LinkAggTraffic {
	public String linkID;
	public int dur;

	public LinkAggTraffic(String linkID, int dur) {
		this.linkID = linkID;
		this.dur = dur;
	}
}

//道路上的聚集度量
class MLinkAggTraffic {
	public String mLinkID = null;
	
	public float startOffset = Float.MAX_VALUE;	
	public float endOffset = Float.MIN_VALUE;
	
	public int startTime = Integer.MAX_VALUE;
	public int endTime = Integer.MIN_VALUE;
	
    public int num; // 聚合的MLinkCluster的数目
    
	public int dur;

	public MLinkAggTraffic(String mLinkID, float startOffset, float endOffset, int startTime, int endTime) {
		this.mLinkID = mLinkID;
		this.startOffset = startOffset;
		this.endOffset = endOffset;
		this.startTime = startTime;
		this.endTime = endTime;
		this.dur = (this.endTime - this.startTime) + 1;
		this.num = 1;
	}
}

